package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"time"

	"github.com/go-chi/chi"
	"github.com/go-chi/jwtauth"
	httpSwagger "github.com/swaggo/http-swagger" // Импортируем Swagger
	"golang.org/x/crypto/bcrypt"
)

// @title Address Geocoding API
// version 1.0
// @description Это API для поиска и геокодирования адресов
// @host localhost:8080
// @BasePath /

// @Summary Запуск сервера
// @Description запускает сервер на порту 8080

type User struct {
	Username string
	Password string
}

var users = map[string]string{} // Хранилище пользователей в памяти (username -> hashed password)

var tokenAuth *jwtauth.JWTAuth

func tokenVerifierMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, claims, err := jwtauth.FromContext(r.Context())
		if err != nil || claims["sub"] == nil {
			http.Error(w, "Forbidden", http.StatusForbidden)
			return
		}
		next.ServeHTTP(w, r)
	})
}

// @Summary Login user
// @Description Logs in a user.
// @Tags users
// @Accept  json
// @Produce  json
// @Param user body User true "User data"
// @Success 200 {string} "JWT Token"
// @Failure 400 {string} "Invalid request format"
// @Failure 401 {string} "Invalid username or password"
// @Router /api/login [post]
func loginHandler(w http.ResponseWriter, r *http.Request) {
	var user User
	err := json.NewDecoder(r.Body).Decode(&user)
	if err != nil || user.Username == "" || user.Password == "" {
		http.Error(w, "Invalid request payload", http.StatusBadRequest)
		return
	}

	// Проверка, существует ли пользователь
	storedPassword, exists := users[user.Username]
	if !exists {
		http.Error(w, "Invalid username or password", http.StatusUnauthorized) // поправил
		return
	}

	// Проверка пароля
	err = bcrypt.CompareHashAndPassword([]byte(storedPassword), []byte(user.Password))
	if err != nil {
		http.Error(w, "Invalid username or password", http.StatusUnauthorized) //  поправил
		return
	}

	// Генерация JWT-токена
	_, tokenString, _ := tokenAuth.Encode(map[string]interface{}{"sub": user.Username, "exp": time.Now().Add(time.Hour * 72).Unix()})
	w.WriteHeader(http.StatusOK)
	json.NewEncoder(w).Encode(map[string]string{"token": tokenString})
}

// @Summary Register a new user
// @Description Registers a new user.
// @Tags users
// @Accept  json
// @Produce  json
// @Param user body User true "User data"
// @Success 201 {string} "User registered successfully"
// @Failure 400 {string} "Invalid request format"
// @Failure 409 {string} "User already exists"
// @Router /api/register [post]
func registerHandler(w http.ResponseWriter, r *http.Request) {
	var user User
	err := json.NewDecoder(r.Body).Decode(&user)
	if err != nil || user.Username == "" || user.Password == "" {
		http.Error(w, "Invalid request payload", http.StatusBadRequest)
		return
	}

	// Хеширование пароля
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
	if err != nil {
		http.Error(w, "Error creating user", http.StatusInternalServerError)
		return
	}

	// Проверка, существует ли пользователь
	if _, exists := users[user.Username]; exists {
		http.Error(w, "User already exists", http.StatusBadRequest)
		return
	}

	// Сохранение пользователя
	users[user.Username] = string(hashedPassword)
	w.WriteHeader(http.StatusCreated)
	fmt.Fprintf(w, "User %s registered successfully", user.Username)
}

// @Summary Search for an address
// @Description Searches for addresses based on a query.
// @Tags address
// @Accept  json
// @Produce  json
// @Success 200 {object} AddressSearchResult
// @Failure 401 {string} "Unauthorized"
// @Router /api/address/search [get]
func addressSearchHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintln(w, "Address search successful")
}

// @Summary Geocode an address
// @Description Geocodes an address.
// @Tags address
// @Accept  json
// @Produce  json
// @Success 200 {object} AddressGeocodeResult
// @Failure 401 {string} "Unauthorized"
// @Router /api/address/geocode [get]
func addressGeocodeHandler(w http.ResponseWriter, r *http.Request) {
	w.WriteHeader(http.StatusOK)
	fmt.Fprintln(w, "Geocoding successful")
}

func main() {
	// Инициализация JWT-аутентификации
	tokenAuth = jwtauth.New("HS256", []byte("mysecretkey"), nil)

	r := chi.NewRouter()

	// Swagger документация
	r.Get("/swagger/*", httpSwagger.Handler(
		httpSwagger.URL("http://localhost:8080/swagger/doc.json"),
	))

	// Регистрация и вход
	r.Post("/api/register", registerHandler)
	r.Post("/api/login", loginHandler)

	// Защищенные маршруты
	r.Group(func(r chi.Router) {
		r.Use(jwtauth.Verifier(tokenAuth))
		r.Use(tokenVerifierMiddleware)
		r.Get("/api/address/search", addressSearchHandler)
		r.Get("/api/address/geocode", addressGeocodeHandler)
	})

	// Запуск сервера
	log.Fatal(http.ListenAndServe(":8080", r))
}
